<?php

declare(strict_types=1);

namespace app\sys\service;

use think\admin\extend\CodeExtend;
use think\admin\model\SysMenu;
use think\admin\model\SysMobileMenu;
use think\admin\model\SysModule;
use think\admin\model\SysSpa;
use think\admin\Service;
use think\admin\service\AdminService;
use think\db\exception\DataNotFoundException;
use think\db\exception\DbException;
use think\db\exception\ModelNotFoundException;

/**
 * 菜单管理服务
 * Class SystemMenuService
 * @package app\system\service
 */
class SystemMenuService extends Service
{
    /**
     * 获取模块及相应菜单
     * @return array
     * @throws DataNotFoundException
     * @throws DbException
     * @throws ModelNotFoundException
     */
    public function getModuleMenus(): array
    {
        $userMenuIds = [];
        if (AdminService::userType() != 'GLOBAL') {
            $merchantId = AdminService::getMerchantId();
            $merchantDetail = AdminService::getMerchantDetail($merchantId);
            $moduleIds = explode(',',$merchantDetail['subName']);
            $map = [['id','in', $moduleIds]];
        } else {
            $map = 1;
        }
        $module = SysModule::mk()->with(['menus'])->where(['is_deleted' => 0])->where($map)->order('sort ASC')->select()->toArray();
        // 非超管用户所拥有的菜单集
        if (!AdminService::isSuper() && !AdminService::isGlobalAdmin()) $userMenuIds = AdminService::getUserMenus();
        if ($module) foreach ($module as &$r) {
            // 模块生成随机路径，及META数组
            $r['path'] = '/' . CodeExtend::random(10, 3);
            $r['meta'] = [
                'icon' => $r['icon'],
                'title' => $r['title'],
                'type' => strtolower($r['category'])
            ];
            // 非超管根据用户拥有的菜单删除无权限菜单
            if (!AdminService::isSuper() && !AdminService::isGlobalAdmin()) {
                foreach ($r['menus'] as $k => $v) {
                    if (!in_array($v['id'], $userMenuIds)) {
                        unset($r['menus'][$k]);
                    }
                }
                // 合并类型为目录的数组，删除菜单后重键值重新排列
                $r['menus'] = array_values($r['menus']);
            }
            // 菜单转树形
            $r['menus'] = self::toTree($r['menus']);
        }
        return $module;
    }

    /**
     * 数组转树结构
     * @param array $data
     * @param int $parentId
     * @param string $id
     * @param string $parentField
     * @param string $children
     * @return array
     */
    public function toTree(array $data = [], int $parentId = 0, string $id = 'id', string $parentField = 'parentId', string $children = 'children'): array
    {
        $tree = [];
        $references = [];

        // 预处理数据，创建引用数组
        foreach ($data as &$item) {
            $references[$item[$id]] = &$item;
            $item[$children] = [];
        }

        // 构建树结构
        foreach ($data as &$item) {
            if ($item[$parentField] == $parentId) {
                $tree[] = &$item;
            } else {
                if (isset($references[$item[$parentField]])) {
                    $references[$item[$parentField]][$children][] = &$item;
                }
            }
        }

        return $tree;
    }


    /**
     * 手机端模块菜单
     * @return array
     * @throws DataNotFoundException
     * @throws DbException
     * @throws ModelNotFoundException
     */
    public function getMobileModuleMenus(): array
    {
        $module = SysMobileMenu::mk()->where(['module'=>10002])->where(['is_deleted' => 0])->order('sort ASC')->select()->toArray();
        // 非超管用户所拥有的菜单集
        //if(!AdminService::isSuper()) $userMenuIds = AdminService::getUserMenus();
        return self::toTree($module);
    }

    /**
     * 获取单页菜单
     * @return array
     * @throws DataNotFoundException
     * @throws DbException
     * @throws ModelNotFoundException
     */
    public function getSpaMenus(): array
    {
        $spa = SysSpa::mk()
            ->where(['is_deleted' => 0])
            ->order('sort ASC')
            ->select()
            ->toArray();
        if ($spa) foreach ($spa as &$r) {
            $r['meta'] = [
                'icon' => $r['icon'],
                'title' => $r['title'],
                'type' => 'menu'
            ];
            if ($r['isTop'] === 0 && $r['isHidden'] === 1) {
                $r['meta']['affix'] = true;
            } else {
                $r['meta']['hidden'] = true;
            }
        }
        return $spa;
    }

    /**
     * 获取最后访问页的模块ID
     * @param string $lastPath
     * @return int
     */
    public function getLastModuleId(string $lastPath): int
    {
        if (!$lastPath) return 10000;//没有LAST，则默认第一个模块
        $id = SysSpa::mk()->where(['is_deleted' => 0, 'status' => 0])->where(['path' => $lastPath])->value('module');
        if (!$id) {
            $id = SysMenu::mk()->where(['is_deleted' => 0, 'status' => 0])->where(['path' => $lastPath])->value('module');
        }
        if ($id) {
            return (int)$id;
        } else {
            return 10000;//没有LAST，则默认第一个模块
        }
    }

    /**
     * 处理模块及单页生成供前台调用的菜单
     * @param array $module
     * @param array $spa
     * @return array
     */
    public function getMenus(array $module, array $spa): array
    {
        if (empty($module) || empty($spa)) return [];
        foreach ($module as &$v) {
            foreach ($v['menus'] as &$value) {
                $value['meta'] = [
                    'icon' => $value['icon'],
                    'title' => $value['title'],
                    'type' => 'menu'
                ];
                if (!empty($value['children'])) {
                    foreach ($value['children'] as &$m) {
                        $m['meta'] = [
                            'icon' => $m['icon'],
                            'title' => $m['title'],
                            'type' => 'menu'
                        ];
                        if ($m['isHidden']) {
                            $m['meta']['hidden'] = true;
                        }
                        if (!empty($m['children'])) unset($m['children']);//去除category为BUTTON的数据
                    }
                }
            }
            $bindApps = $this->bindApps($v['id'], $spa);
            //if($k===0){
            //$v['menus'] = array_merge($spa,$v['menus']);
            //}
            $v['menus'] = array_merge($bindApps, $v['menus']);
            $v['children'] = $v['menus'];
            unset($v['menus']);
        }
        return $module;
    }

    /**
     * 模块绑定单页
     * @param int $moduleId
     * @param array $spa
     * @return array
     */
    protected function bindApps(int $moduleId, array $spa): array
    {
        $bindApp = [];
        foreach ($spa as $s) {
            if (in_array($moduleId, explode(',', $s['module'] . ''))) {
                $bindApp[] = $s;
            }
        }
        return $bindApp;
    }

    /**
     * 获取手机端菜单
     * @param array $module
     * @return array
     */
    public function getMobileMenus(array $module): array
    {
        if (empty($module)) return [];
        foreach ($module as &$v) {
            foreach ($v['menus'] as &$value) {
                $value['meta'] = [
                    'icon' => $value['icon'],
                    'title' => $value['title'],
                    'type' => 'menu'
                ];
                if (!empty($value['children'])) {
                    foreach ($value['children'] as &$m) {
                        $m['meta'] = [
                            'icon' => $m['icon'],
                            'title' => $m['title'],
                            'type' => 'menu'
                        ];
                        if ($m['isHidden']) {
                            $m['meta']['hidden'] = true;
                        }
                        if (!empty($m['children'])) unset($m['children']);//去除category为BUTTON的数据
                    }
                }
            }
            $v['children'] = $v['menus'];
            unset($v['menus']);
        }
        return $module;
    }

    /**
     * 获取所有菜单、按钮、API权限资源
     * @return array
     * @throws DataNotFoundException
     * @throws DbException
     * @throws ModelNotFoundException
     */
    public function getResourceTree(): array
    {
        $module = SysModule::mk()->with(['menus'])->where(['is_deleted' => 0])->field('id,icon,title')->order('sort ASC')->select()->toArray();
        if (empty($module)) return [];
        foreach ($module as &$v) {
            $v['menu'] = [];
            foreach ($v['menus'] as $value) {
                // 数组menus生成用于前端的menu数组,将上级ID大于0的处理成前端所需格式
                if ($value['parentId'] > 0) {
                    $v['menu'][] = [
                        'title' => $value['title'],
                        'parentName' => searchByValue($v['menus'], 'id', $value['parentId'], 'title') . '[' . $v['id'] . ']',//搜索菜单数组上组菜单名称
                        'parentId' => $value['parentId'],
                        'module' => $value['module'],
                        'category' => $value['category'],
                        'id' => $value['id'],
                        'button' => searchByArr($v['menus'], 'parentId', $value['id'], ['category' => 'BUTTON'])//搜索菜单数组分类为BUTTON的转成对应数组格式
                    ];
                }
            }
            //删除原menus数组
            unset($v['menus']);
        }
        //将最新数组分类为BUTTON的菜单组删除
        foreach ($module as &$vv) {
            foreach ($vv['menu'] as $k => $vvv) {
                if ($vvv['category'] === 'BUTTON') {
                    unset($vv['menu'][$k]);
                }
            }
            //重新排列键值
            $vv['menu'] = array_values($vv['menu']);
        }
        return $module;
    }

    /**
     * 获取权限
     * @param string $category
     * @return array
     * @throws DataNotFoundException
     * @throws DbException
     * @throws ModelNotFoundException
     */
    public function getPermissions(string $category = 'biz'): array
    {
        if ($category != 'GLOBAL') {
            $map = ['code' => 'BIZ'];
        } else {
            $map = 1;
        }
        $module = SysModule::mk()
            ->with(['menus'])
            ->where($map)
            ->where(['is_deleted' => 0])
            ->field('id,icon,title')
            ->order('sort ASC')
            ->select()
            ->toArray();
        if (empty($module)) return [];
        $permission = [];
        foreach ($module as $v) {
            foreach ($v['menus'] as $value) {
                if ($value['code'] != '' && $value['category'] === 'MENU') { // 由原所有API修改为限制分类为MENU的API（2023/05/13）
                    $permission[] = $value['code'] . '[' . $value['title'] . ']';
                }
            }
        }
        unset($module);
        return $permission;
    }

    /**
     * 获取一个子系统的菜单、按钮、API权限资源
     * @param int $moduleId
     * @return array
     * @throws DataNotFoundException
     * @throws DbException
     * @throws ModelNotFoundException
     */
    public function getOneResourceTree(int $moduleId): array
    {
        $module = SysModule::mk()->with(['menus'])->where(['id' => $moduleId])->where(['is_deleted' => 0])->field('id,icon,title')->order('sort ASC')->select()->toArray();
        if (empty($module)) return [];
        foreach ($module as &$v) {
            $v['menu'] = [];
            foreach ($v['menus'] as $value) {
                // 数组menus生成用于前端的menu数组,将上级ID大于0的处理成前端所需格式
                if ($value['parentId'] > 0) {
                    $v['menu'][] = [
                        'title' => $value['title'],
                        'parentName' => searchByValue($v['menus'], 'id', $value['parentId'], 'title'),//搜索菜单数组上组菜单名称
                        'parentId' => $value['parentId'],
                        'module' => $value['module'],
                        'category' => $value['category'],
                        'id' => $value['id']
                    ];
                }
            }
            //删除原menus数组
            unset($v['menus']);
        }
        //将最新数组分类为BUTTON的菜单组删除
        foreach ($module as &$vv) {
            foreach ($vv['menu'] as $k => $vvv) {
                if ($vvv['category'] === 'BUTTON') {
                    unset($vv['menu'][$k]);
                }
            }
            //重新排列键值
            $vv['menu'] = array_values($vv['menu']);
        }
        return $module;
    }
}
